# -*- coding: utf-8 -*-
# =============================================================================
#         Desc: 使用mysqlbinlog命令对binlog进行分析找出
#               1、执行时间较长事务。
#               2、影响行数较多事务。
#               3、产生Binlog量较大的事务。
#       Author: GGA
#        Email:
#     HomePage:
#      Version: 1.0.0
#   LastChange: 2020-12-20
#      History:
# =============================================================================
import os
import sys
import subprocess
import logging
import fire
from utils.logger_helper import LoggerHelper

logger = LoggerHelper.get_logger()


class CommonConfig(object):
    # mysqlbinlog文件路径
    mysql_binlog_exe = "mysqlbinlog"


class TableAction(object):
    def __init__(self, table_name):
        self.table_name = table_name
        self.insert = 0
        self.update = 0
        self.delete = 0

    @property
    def total(self):
        return self.insert + self.update + self.delete


class BinlogTableChecker(object):

    @classmethod
    def show_check_results(cls, table_dict):
        table_items = sorted(table_dict.values(), key=lambda x: x["TOTAL"], reverse=True)
        check_results = list()
        check_results.append("")
        check_results.append("表操作统计如下:")
        table_action_format = "|{:>10}|{:>10}|{:>10}|{:>10}|{:64}|"
        table_header1 = table_action_format.format("-" * 10, "-" * 10, "-" * 10, "-" * 10, "-" * 64)
        check_results.append(table_header1)
        table_header2 = table_action_format.format("TOTAL", "INSERT", "DELETE", "UPDATE", "TABLE_NAME")
        check_results.append(table_header2)
        check_results.append(table_header1)
        row_count = 0
        for table_item in table_items:
            msg = table_action_format.format(
                table_item["TOTAL"], table_item["INSERT"],
                table_item["DELETE"],table_item["UPDATE"],
                table_item["TABLE_NAME"])
            check_results.append(msg)
            row_count += 1
            if row_count % 50 == 0:
                check_results.append(table_header1)
                check_results.append(table_header2)
                check_results.append(table_header1)
            pass
        check_results.append(table_header1)
        logger.info("\r\n".join(check_results))

    @classmethod
    def get_table_summary(cls, binlog_path: str, start_time: str = None, stop_time: str = None):
        logger.info("开始检查文件：{}".format(binlog_path))
        cmd = " {} -v --base64-output=DECODE-ROWS '{}' "
        cmd = cmd.format(
            CommonConfig.mysql_binlog_exe, binlog_path
        )
        if start_time is not None:
            cmd += " --start-datetime='{}' ".format(start_time)
        if stop_time is not None:
            cmd += " --stop-datetime='{}' ".format(stop_time)
        cmd += " | egrep '^### INSERT INTO|^### UPDATE|^### DELETE FROM' "
        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        line_num = 0
        table_dict = dict()
        while True:
            line_num += 1
            if line_num % 10000 == 0:
                logger.info("处理记录行：{}".format(line_num))
            file_bytes = p.stdout.readline()
            if not file_bytes:
                break
            file_line = file_bytes.decode().strip()
            table_name = (
                file_line.replace("### INSERT INTO", "")
                .replace("### UPDATE", "")
                .replace("### DELETE FROM", "")
                .strip()
            )
            if table_name not in table_dict:
                table_dict[table_name] = {
                    "TABLE_NAME": table_name,
                    "INSERT": 0,
                    "UPDATE": 0,
                    "DELETE": 0,
                    "TOTAL": 0
                }
            tba = table_dict[table_name]
            if file_line.startswith("### INSERT INTO"):
                table_dict[table_name]["INSERT"] += 1
                table_dict[table_name]["TOTAL"] += 1
            if file_line.startswith("### UPDATE"):
                table_dict[table_name]["UPDATE"] += 1
                table_dict[table_name]["TOTAL"] += 1
            if file_line.startswith("### DELETE FROM"):
                table_dict[table_name]["DELETE"] += 1
                table_dict[table_name]["TOTAL"] += 1
        logger.info("检查文件完成：{}".format(binlog_path))
        cls.show_check_results(table_dict)


def init_logger():
    LoggerHelper.init_logger(logger_level=logging.INFO)
    global logger
    logger = LoggerHelper.get_logger()


def main(binlog_path="", start_time: str = None, stop_time: str = None):
    """
    获取指定BINLOG内每个表的修改操作次数
    :param binlog_path: binlog文件地址
    :param start_time: 开始时间,格式为 2023-01-01 12:00:00
    :param stop_time: 结束时间,格式为 2023-01-01 12:00:00
    :return:
    """
    if not os.path.exists(binlog_path):
        logger.info("指定的文件不存在,请重试！")
        return
    BinlogTableChecker.get_table_summary(binlog_path, start_time, stop_time)


if __name__ == '__main__':
    init_logger()
    fire.Fire(main)
